/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.cachecontrol;

import com.softwarecraftsmen.cachecontrol.cacheFactories.CacheFactory;
import com.softwarecraftsmen.cachecontrol.keys.Key;
import com.softwarecraftsmen.cachecontrol.keys.SimpleKey;
import com.softwarecraftsmen.cachecontrol.keys.IdentityKey;
import static com.softwarecraftsmen.cachecontrol.IsSame.isSame;
import com.softwarecraftsmen.cachecontrol.caches.ThreadSafeHashMapCache;
import org.jetbrains.annotations.NotNull;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;

public class CashierTest
{
	@Test(expected=UnsupportedOperationException.class)
	public void defaultConstructorDoesNotSupportCreatingCachesIfTheyDoNotExist()
	{
		new Cashier().dispense(identifier);
	}

	@Test
	public void dispensesConsistentlyTheSameCacheReferenceForTheSameKey()
	{
		final Cache<String> firstTime = dispense();
		final Cache<String> secondTime = dispense();

		Assert.assertThat(secondTime, isSame(firstTime));
	}

	@Test
	public void invalidatingCacheClearsAllEntries()
	{
		final Cache<String> cache = dispense();
		final SimpleKey<String> key = new SimpleKey<String>("X");

		cache.store(key, "something");
		assertCacheItemStatus(key, true);

		cashier.invalidateCache(identifier);
		assertCacheItemStatus(key, false);
	}

	@Test
	public void invalidatingAllCachesClearsAllEntries()
	{
		final Key<String> cache1Identifier = IdentityKey.unique();
		final Cache<String> cache1 = cashier.dispense(cache1Identifier);
		cache1.at("anyKey").put("something");

		final Key<String> cache2Identifier = IdentityKey.unique();
		final Cache<String> cache2 = cashier.dispense(cache2Identifier);
		cache2.at("anyKey").put("something");

		cashier.invalidateAllCaches();

		assertTrue(cache1.obtain("anyKey").isEmpty());
		assertTrue(cache2.obtain("anyKey").isEmpty());
	}

	@Before
	public void before()
	{
		identifier = new SimpleKey<String>("Hello");
		cashier = new Cashier(new CacheFactory()
		{
			@NotNull
			public <V> ComptrolledCache<V> create(@NotNull final Key<V> identifier)
			{
				return new ThreadSafeHashMapCache<V>(identifier);
			}
		});
	}

	private SimpleKey<String> identifier;
	private Cashier cashier;

	private void assertCacheItemStatus(final Key<String> key, final boolean hasValueStatus)
	{
		final Item<?> hasValue = dispense().obtain(key);
		assertEquals(hasValueStatus, hasValue.hasValue());
	}

	private Cache<String> dispense() {return cashier.dispense(identifier);}
}
